home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / dev / c / qtools0.2-src.lha / src / libqbuild / light.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-15  |  21.3 KB  |  836 lines

  1. #define    LIBQBUILD_CORE
  2. #include "../include/libqbuild.h"
  3.  
  4. int c_bad;
  5. struct tnode *tnodes, *tnode_p;
  6. bool *nolightface;
  7. float *minlights;
  8. float rangescale = 0.5;
  9. float scalecos = 0.5;
  10. float scaledist = 1.0;
  11. int bspfileface;                        /* next surface to dispatch */
  12. vec3_t *faceoffset;
  13. vec3_t bsp_origin;
  14.  
  15. /*
  16.  * ==============================================================================
  17.  * 
  18.  * LINE TRACING
  19.  * 
  20.  * The major lighting operation is a point to point visibility test, performed
  21.  * by recursive subdivision of the line by the BSP tree.
  22.  * 
  23.  * ==============================================================================
  24.  */
  25.  
  26. bool TestLine(vec3_t start, vec3_t stop)
  27. {
  28.   int node;
  29.   float front, back;
  30.   tracestack_t *tstack_p;
  31.   int side;
  32.   float frontx, fronty, frontz, backx, backy, backz;
  33.   tracestack_t tracestack[64];
  34.   struct tnode *tnode;
  35.  
  36.   frontx = start[0];
  37.   fronty = start[1];
  38.   frontz = start[2];
  39.   backx = stop[0];
  40.   backy = stop[1];
  41.   backz = stop[2];
  42.  
  43.   tstack_p = tracestack;
  44.   node = 0;
  45.  
  46.   while (1) {
  47.     while (node < 0 && node != CONTENTS_SOLID) {
  48.       /* pop up the stack for a back side */
  49.       tstack_p--;
  50.       if (tstack_p < tracestack)
  51.     return TRUE;
  52.       node = tstack_p->node;
  53.  
  54.       /* set the hit point for this plane */
  55.  
  56.       frontx = backx;
  57.       fronty = backy;
  58.       frontz = backz;
  59.  
  60.       /* go down the back side */
  61.  
  62.       backx = tstack_p->backpt[0];
  63.       backy = tstack_p->backpt[1];
  64.       backz = tstack_p->backpt[2];
  65.  
  66.       node = tnodes[tstack_p->node].children[!tstack_p->side];
  67.     }
  68.  
  69.     if (node == CONTENTS_SOLID)
  70.       return FALSE;                        /* DONE! */
  71.  
  72.     tnode = &tnodes[node];
  73.  
  74.     switch (tnode->type) {
  75.       case PLANE_X:
  76.     front = frontx - tnode->dist;
  77.     back = backx - tnode->dist;
  78.     break;
  79.       case PLANE_Y:
  80.     front = fronty - tnode->dist;
  81.     back = backy - tnode->dist;
  82.     break;
  83.       case PLANE_Z:
  84.     front = frontz - tnode->dist;
  85.     back = backz - tnode->dist;
  86.     break;
  87.       default:
  88.     front = (frontx * tnode->normal[0] + fronty * tnode->normal[1] + frontz * tnode->normal[2]) - tnode->dist;
  89.     back = (backx * tnode->normal[0] + backy * tnode->normal[1] + backz * tnode->normal[2]) - tnode->dist;
  90.     break;
  91.     }
  92.  
  93.     if (front > -ON_EPSILON && back > -ON_EPSILON) {
  94.       node = tnode->children[0];
  95.       continue;
  96.     }
  97.  
  98.     if (front < ON_EPSILON && back < ON_EPSILON) {
  99.       node = tnode->children[1];
  100.       continue;
  101.     }
  102.  
  103.     side = front < 0;
  104.  
  105.     front = front / (front - back);
  106.  
  107.     tstack_p->node = node;
  108.     tstack_p->side = side;
  109.     tstack_p->backpt[0] = backx;
  110.     tstack_p->backpt[1] = backy;
  111.     tstack_p->backpt[2] = backz;
  112.  
  113.     tstack_p++;
  114.  
  115.     backx = frontx + front * (backx - frontx);
  116.     backy = fronty + front * (backy - fronty);
  117.     backz = frontz + front * (backz - frontz);
  118.  
  119.     node = tnode->children[side];
  120.   }
  121. }
  122.  
  123. /*
  124.  * ============
  125.  * CastRay
  126.  * 
  127.  * Returns the distance between the points, or -1 if blocked
  128.  * =============
  129.  */
  130. vec_t CastRay(register vec3_t p1, register vec3_t p2)
  131. {
  132.   short int i;
  133.   vec_t t;
  134.  
  135.   if (!TestLine(p1, p2))
  136.     return -1;                            /* ray was blocked */
  137.  
  138.   t = 0;
  139.   for (i = 0; i < 3; i++)
  140.     t += (p2[i] - p1[i]) * (p2[i] - p1[i]);
  141.  
  142.   if (t == 0)
  143.     t = 1;                            /* don't blow up... */
  144.  
  145.   return sqrt(t);
  146. }
  147.  
  148. /*
  149.  * ===================================================================
  150.  * 
  151.  * TRANSFER SCALES
  152.  * 
  153.  * ===================================================================
  154.  */
  155.  
  156. /*
  157.  * ==============
  158.  * MakeTnode
  159.  * 
  160.  * Converts the disk node structure into the efficient tracing structure
  161.  * ==============
  162.  */
  163. void MakeTnode(__memBase, register int nodenum)
  164. {
  165.   struct tnode *t;
  166.   struct dplane_t *plane;
  167.   short int i;
  168.   struct dnode_t *node;
  169.  
  170.   t = tnode_p++;
  171.  
  172.   node = bspMem->shared.quake1.dnodes + nodenum;
  173.   plane = bspMem->shared.quake1.dplanes + node->planenum;
  174.  
  175.   t->type = plane->type;
  176.   VectorCopy(plane->normal, t->normal);
  177.   t->dist = plane->dist;
  178.  
  179.   for (i = 0; i < 2; i++) {
  180.     if (node->children[i] < 0)
  181.       t->children[i] = bspMem->shared.quake1.dleafs[-node->children[i] - 1].contents;
  182.     else {
  183.       t->children[i] = tnode_p - tnodes;
  184.       MakeTnode(bspMem, node->children[i]);
  185.     }
  186.   }
  187.  
  188. }
  189.  
  190. /*
  191.  * =============
  192.  * MakeTnodes
  193.  * 
  194.  * Loads the node structure out of a .bsp file to be used for light occlusion
  195.  * =============
  196.  */
  197. void MakeTnodes(__memBase, register struct dmodel_t *bm)
  198. {
  199.   if (!(tnode_p = tnodes = (struct tnode *)kmalloc(bspMem->shared.quake1.numnodes * sizeof(struct tnode))))
  200.       Error(failed_memoryunsize, "tnode");
  201.  
  202.   MakeTnode(bspMem, 0);
  203. }
  204.  
  205. /*
  206.  * ===============================================================================
  207.  * 
  208.  * SAMPLE POINT DETERMINATION
  209.  * 
  210.  * void SetupBlock (dface_t *f) Returns with surfpt[] set
  211.  * 
  212.  * This is a little tricky because the lightmap covers more area than the face.
  213.  * If done in the straightforward fashion, some of the
  214.  * sample points will be inside walls or on the other side of walls, causing
  215.  * FALSE shadows and light bleeds.
  216.  * 
  217.  * To solve this, I only consider a sample point valid if a line can be drawn
  218.  * between it and the exact midpoint of the face.  If invalid, it is adjusted
  219.  * towards the center until it is valid.
  220.  * 
  221.  * (this doesn't completely work)
  222.  * 
  223.  * ===============================================================================
  224.  */
  225.  
  226. /*
  227.  * ================
  228.  * CalcFaceVectors
  229.  * 
  230.  * Fills in texorg, worldtotex. and textoworld
  231.  * ================
  232.  */
  233. void CalcFaceVectors(__memBase, register struct lightinfo *l)
  234. {
  235.   struct texinfo *tex;
  236.   short int i, j;
  237.   vec3_t texnormal;
  238.   float distscale;
  239.   vec_t dist, len;
  240.  
  241.   tex = &bspMem->shared.quake1.texinfo[l->face->texinfo];
  242.  
  243.   /* convert from float to vec_t */
  244.   for (i = 0; i < 2; i++)
  245.     for (j = 0; j < 3; j++)
  246.       l->worldtotex[i][j] = tex->vecs[i][j];
  247.  
  248.   /*
  249.    * calculate a normal to the texture axis.  points can be moved along this
  250.    * without changing their S/T
  251.    */
  252.   texnormal[0] = tex->vecs[1][1] * tex->vecs[0][2] - tex->vecs[1][2] * tex->vecs[0][1];
  253.   texnormal[1] = tex->vecs[1][2] * tex->vecs[0][0] - tex->vecs[1][0] * tex->vecs[0][2];
  254.   texnormal[2] = tex->vecs[1][0] * tex->vecs[0][1] - tex->vecs[1][1] * tex->vecs[0][0];
  255.   VectorNormalize(texnormal);
  256.  
  257.   /* flip it towards plane normal */
  258.   distscale = DotProduct(texnormal, l->facenormal);
  259.   if (!distscale)
  260.     Error("Texture axis perpendicular to face\n"
  261.       "Face point at ( %g %g %g )\n",
  262.       bspMem->shared.quake1.dvertexes[bspMem->shared.quake1.dedges[l->face->firstedge].v[0]].point[0],
  263.       bspMem->shared.quake1.dvertexes[bspMem->shared.quake1.dedges[l->face->firstedge].v[0]].point[1],
  264.       bspMem->shared.quake1.dvertexes[bspMem->shared.quake1.dedges[l->face->firstedge].v[0]].point[2]);
  265.   if (distscale < 0) {
  266.     distscale = -distscale;
  267.     VectorNegate(texnormal);
  268.   }
  269.  
  270.   /*
  271.    * distscale is the ratio of the distance along the texture normal to
  272.    * the distance along the plane normal
  273.    */
  274.   distscale = 1 / distscale;
  275.  
  276.   for (i = 0; i < 2; i++) {
  277.     len = VectorLength(l->worldtotex[i]);
  278.     dist = DotProduct(l->worldtotex[i], l->facenormal);
  279.     dist *= distscale;
  280.     VectorMA(l->worldtotex[i], -dist, texnormal, l->textoworld[i]);
  281.     VectorScale(l->textoworld[i], (1 / len) * (1 / len), l->textoworld[i]);
  282.   }
  283.  
  284.   /* calculate texorg on the texture plane */
  285.   for (i = 0; i < 3; i++)
  286.     l->texorg[i] = -tex->vecs[0][3] * l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i];
  287.  
  288.   /* project back to the face plane */
  289.   dist = DotProduct(l->texorg, l->facenormal) - l->facedist - 1;
  290.   dist *= distscale;
  291.   VectorMA(l->texorg, -dist, texnormal, l->texorg);
  292.  
  293. }
  294.  
  295. /*
  296.  * ================
  297.  * CalcFaceExtents
  298.  * 
  299.  * Fills in s->texmins[] and s->texsize[]
  300.  * also sets exactmins[] and exactmaxs[]
  301.  * ================
  302.  */
  303. void CalcFaceExtents(__memBase, register struct lightinfo *l, register vec3_t faceoffset)
  304. {
  305.   struct dface_t *s;
  306.   vec_t mins[2], maxs[2], val;
  307.   int i, e;
  308.   short int j;
  309.   struct dvertex_t *v;
  310.   struct texinfo *tex;
  311.  
  312.   s = l->face;
  313.  
  314.   mins[0] = mins[1] = 999999;
  315.   maxs[0] = maxs[1] = -99999;
  316.  
  317.   tex = &bspMem->shared.quake1.texinfo[s->texinfo];
  318.  
  319.   for (i = 0; i < s->numedges; i++) {
  320.     e = bspMem->shared.quake1.dsurfedges[s->firstedge + i];
  321.     if (e >= 0)
  322.       v = bspMem->shared.quake1.dvertexes + bspMem->shared.quake1.dedges[e].v[0];
  323.     else
  324.       v = bspMem->shared.quake1.dvertexes + bspMem->shared.quake1.dedges[-e].v[1];
  325.  
  326.     for (j = 0; j < 2; j++) {
  327.       val = (v->point[0] + faceoffset[0]) * tex->vecs[j][0] +
  328.     (v->point[1] + faceoffset[1]) * tex->vecs[j][1] +
  329.     (v->point[2] + faceoffset[2]) * tex->vecs[j][2] +
  330.     tex->vecs[j][3];
  331.       if (val < mins[j])
  332.     mins[j] = val;
  333.       if (val > maxs[j])
  334.     maxs[j] = val;
  335.     }
  336.   }
  337.  
  338.   for (i = 0; i < 2; i++) {
  339.     l->exactmins[i] = mins[i];
  340.     l->exactmaxs[i] = maxs[i];
  341.  
  342.     mins[i] = floor(mins[i] / 16);
  343.     maxs[i] = ceil(maxs[i] / 16);
  344.  
  345.     l->texmins[i] = mins[i];
  346.     l->texsize[i] = maxs[i] - mins[i];
  347.     if (l->texsize[i] > 17)
  348.       Error("Bad surface extents\n");
  349.   }
  350. }
  351.  
  352. /*
  353.  * =================
  354.  * CalcPoints
  355.  * 
  356.  * For each texture aligned grid point, back project onto the plane
  357.  * to get the world xyz value of the sample point
  358.  * =================
  359.  */
  360. void CalcPoints(__memBase, struct lightinfo *l, register float sofs, register float tofs)
  361. {
  362.   int s, t;
  363.   short int i, j;
  364.   int w, h, step;
  365.   vec_t starts, startt, us, ut;
  366.   vec_t *surf;
  367.   vec_t mids, midt;
  368.   vec3_t facemid, move;
  369.  
  370.   /*
  371.    * fill in surforg
  372.    * the points are biased towards the center of the surface
  373.    * to help avoid edge cases just inside walls
  374.    */
  375.   surf = l->surfpt[0];
  376.   mids = (l->exactmaxs[0] + l->exactmins[0]) / 2;
  377.   midt = (l->exactmaxs[1] + l->exactmins[1]) / 2;
  378.  
  379.   for (j = 0; j < 3; j++)
  380.     facemid[j] = l->texorg[j] + l->textoworld[0][j] * mids + l->textoworld[1][j] * midt;
  381.  
  382.   if ((bspMem->litOptions & LIGHT_EXTRA) && !(bspMem->litOptions & LIGHT_RADIOSITY)) {    /* extra filtering */
  383.     h = (l->texsize[1] + 1) * 2;
  384.     w = (l->texsize[0] + 1) * 2;
  385.     starts = (l->texmins[0] - 0.5) * 16;
  386.     startt = (l->texmins[1] - 0.5) * 16;
  387.     step = 8;
  388.   }
  389.   else {
  390.     h = l->texsize[1] + 1;
  391.     w = l->texsize[0] + 1;
  392.     starts = l->texmins[0] * 16;
  393.     startt = l->texmins[1] * 16;
  394.     step = 16;
  395.   }
  396.  
  397.   l->numsurfpt = w * h;
  398.   for (t = 0; t < h; t++) {
  399.     for (s = 0; s < w; s++, surf += 3) {
  400.       us = starts + ((s + sofs) * step);
  401.       ut = startt + ((t + tofs) * step);
  402.  
  403.       /* if a line can be traced from surf to facemid, the point is good */
  404.       for (i = 0; i < 6; i++) {
  405.     /* calculate texture point */
  406.     for (j = 0; j < 3; j++)
  407.       surf[j] = l->texorg[j] + l->textoworld[0][j] * us + l->textoworld[1][j] * ut;
  408.  
  409.     if (TestLine(facemid, surf))
  410.       break;                        /* got it */
  411.  
  412.     if (i & 1) {
  413.       if (us > mids) {
  414.         us -= 8;
  415.         if (us < mids)
  416.           us = mids;
  417.       }
  418.       else {
  419.         us += 8;
  420.         if (us > mids)
  421.           us = mids;
  422.       }
  423.     }
  424.     else {
  425.       if (ut > midt) {
  426.         ut -= 8;
  427.         if (ut < midt)
  428.           ut = midt;
  429.       }
  430.       else {
  431.         ut += 8;
  432.         if (ut > midt)
  433.           ut = midt;
  434.       }
  435.     }
  436.  
  437.     /* move surf 8 pixels towards the center */
  438.     VectorSubtract(facemid, surf, move);
  439.     VectorNormalize(move);
  440.     VectorMA(surf, 8, move, surf);
  441.       }
  442.       if (i == 2)
  443.     c_bad++;
  444.     }
  445.   }
  446.  
  447. }
  448.  
  449. /*
  450.  * ===============================================================================
  451.  * 
  452.  * FACE LIGHTING
  453.  * 
  454.  * ===============================================================================
  455.  */
  456.  
  457. int c_culldistplane, c_proper;
  458.  
  459. /*
  460.  * ================
  461.  * SingleLightFace
  462.  * ================
  463.  */
  464. void SingleLightFace(register struct entity *light, register struct lightinfo *l, register vec3_t faceoffset)
  465. {
  466.   vec_t dist;
  467.   vec3_t incoming;
  468.   vec_t angle;
  469.   vec_t add;
  470.   vec_t *surf;
  471.   bool hit;
  472.   int mapnum;
  473.   int size;
  474.   int c, i;
  475.   vec3_t rel;
  476.   vec3_t spotvec;
  477.   vec_t falloff;
  478.   vec_t *lightsamp;
  479.  
  480.   VectorSubtract(light->origin, bsp_origin, rel);
  481.   /*VectorSubtract (rel, faceoffset, rel); */
  482.   dist = scaledist * (DotProduct(rel, l->facenormal) - l->facedist);
  483.  
  484.   /* don't bother with lights behind the surface */
  485.   if (dist <= 0)
  486.     return;
  487.  
  488.   /* don't bother with light too far away */
  489.   if (dist > light->light) {
  490.     c_culldistplane++;
  491.     return;
  492.   }
  493.  
  494.   if (light->targetent) {
  495.     VectorSubtract(light->targetent->origin, light->origin, spotvec);
  496.     VectorNormalize(spotvec);
  497.     if (!light->angle)
  498.       falloff = -cos(20 * Q_PI / 180);
  499.     else
  500.       falloff = -cos(light->angle / 2 * Q_PI / 180);
  501.   }
  502.   else
  503.     falloff = 0;                        /* shut up compiler warnings */
  504.  
  505.   mapnum = 0;
  506.   for (mapnum = 0; mapnum < l->numlightstyles; mapnum++)
  507.     if (l->lightstyles[mapnum] == light->style)
  508.       break;
  509.   lightsamp = l->lightmaps[mapnum];
  510.   if (mapnum == l->numlightstyles) {                /* init a new light map */
  511.     if (mapnum >= MAXLIGHTMAPS) {
  512.       eprintf("Too many light styles on a face\n");
  513.       return;
  514.     }
  515.     size = (l->texsize[1] + 1) * (l->texsize[0] + 1);
  516.     for (i = 0; i < size; i++)
  517.       lightsamp[i] = 0;
  518.   }
  519.  
  520.   /* check it for real */
  521.   hit = FALSE;
  522.   c_proper++;
  523.  
  524.   surf = l->surfpt[0];
  525.   for (c = 0; c < l->numsurfpt; c++, surf += 3) {
  526.     if ((dist = CastRay(light->origin, surf) * scaledist) < 0)
  527.       continue;                            /* light doesn't reach */
  528.  
  529.     VectorSubtract(light->origin, surf, incoming);
  530.     VectorNormalize(incoming);
  531.     angle = DotProduct(incoming, l->facenormal);
  532.     if (light->targetent) {                    /* spotlight cutoff */
  533.       if (DotProduct(spotvec, incoming) > falloff)
  534.     continue;
  535.     }
  536.  
  537.     angle = (1.0 - scalecos) + scalecos * angle;
  538.     add = light->light - dist;
  539.     add *= angle;
  540.     if (add < 0)
  541.       continue;
  542.     lightsamp[c] += add;
  543.     if (lightsamp[c] > 1)                    /* ignore real tiny lights */
  544.       hit = TRUE;
  545.   }
  546.  
  547.   if (mapnum == l->numlightstyles && hit) {
  548.     l->lightstyles[mapnum] = light->style;
  549.     l->numlightstyles++;                    /* the style has some real data now */
  550.   }
  551. }
  552.  
  553. /*
  554.  * ============
  555.  * FixMinlight
  556.  * ============
  557.  */
  558. void FixMinlight(register struct lightinfo *l)
  559. {
  560.   int i, j;
  561.   float minlight;
  562.  
  563.   minlight = minlights[l->surfnum];
  564.  
  565.   /* if minlight is set, there must be a style 0 light map */
  566.   if (!minlight)
  567.     return;
  568.  
  569.   for (i = 0; i < l->numlightstyles; i++) {
  570.     if (l->lightstyles[i] == 0)
  571.       break;
  572.   }
  573.   if (i == l->numlightstyles) {
  574.     if (l->numlightstyles >= MAXLIGHTMAPS)
  575.       return;                            /* oh well.. */
  576.  
  577.     for (j = 0; j < l->numsurfpt; j++)
  578.       l->lightmaps[i][j] = minlight;
  579.     l->lightstyles[i] = 0;
  580.     l->numlightstyles++;
  581.   }
  582.   else {
  583.     for (j = 0; j < l->numsurfpt; j++)
  584.       if (l->lightmaps[i][j] < minlight)
  585.     l->lightmaps[i][j] = minlight;
  586.   }
  587. }
  588.  
  589. unsigned char *GetFileSpace(__memBase, register int size)
  590. {
  591.   unsigned char *ret;
  592.  
  593.   size = ((size + 3) & ~3);
  594.   if (bspMem->shared.quake1.lightdatasize + size >= bspMem->shared.quake1.max_lightdatasize)
  595.     ExpandClusters(bspMem, LUMP_LIGHTING);
  596.   ret = bspMem->shared.quake1.dlightdata + bspMem->shared.quake1.lightdatasize;
  597.   bspMem->shared.quake1.lightdatasize += size;
  598.  
  599.   return ret;
  600. }
  601.  
  602. /*
  603.  * ============
  604.  * LightFace
  605.  * ============
  606.  */
  607. void LightFace(__memBase, register int facenum, register bool nolight, register vec3_t faceoffset)
  608. {
  609.   struct dface_t *f;
  610.   struct lightinfo l;
  611.   int s, t;
  612.   short int i, j, c;
  613.   vec_t total;
  614.   int size;
  615.   int lightmapwidth, lightmapsize;
  616.   unsigned char *out;
  617.   vec_t *light;
  618.   int w, h;
  619.   vec3_t point;
  620.  
  621.   f = bspMem->shared.quake1.dfaces + facenum;
  622.  
  623.   /* some surfaces don't need lightmaps */
  624.   f->lightofs = -1;
  625.   for (j = 0; j < MAXLIGHTMAPS; j++)
  626.     f->styles[j] = 255;
  627.  
  628.   if ((bspMem->shared.quake1.texinfo[f->texinfo].flags & TEX_SPECIAL)) {    /* non-lit texture */
  629.     if (bspMem->litOptions & LIGHT_WATERLIT) {
  630.       int *textures = (int *)(bspMem->shared.quake1.dtexdata + 4);
  631.       struct mipmap *tex = (struct mipmap *)(bspMem->shared.quake1.dtexdata + textures[bspMem->shared.quake1.texinfo[f->texinfo].miptex]);
  632.  
  633.       if (!__strcmp(tex->name, "sky"))
  634.     return;
  635.     }
  636.     else
  637.       return;
  638.   }
  639.   __bzero(&l, sizeof(l));
  640.   l.surfnum = facenum;
  641.   l.face = f;
  642.  
  643.   /* rotate plane */
  644.   VectorCopy(bspMem->shared.quake1.dplanes[f->planenum].normal, l.facenormal);
  645.   l.facedist = bspMem->shared.quake1.dplanes[f->planenum].dist;
  646.   VectorScale(l.facenormal, l.facedist, point);
  647.   VectorAdd(point, faceoffset, point);
  648.   l.facedist = DotProduct(point, l.facenormal);
  649.  
  650.   if (f->side) {
  651.     VectorNegate(l.facenormal);
  652.     l.facedist = -l.facedist;
  653.   }
  654.  
  655.   CalcFaceVectors(bspMem, &l);
  656.   CalcFaceExtents(bspMem, &l, faceoffset);
  657.   CalcPoints(bspMem, &l, 0, 0);
  658.  
  659.   lightmapwidth = l.texsize[0] + 1;
  660.   size = lightmapwidth * (l.texsize[1] + 1);
  661.   if (size > SINGLEMAP)
  662.     Error("Bad lightmap size");
  663.  
  664.   for (i = 0; i < MAXLIGHTMAPS; i++)
  665.     l.lightstyles[i] = 255;
  666.  
  667.   /* cast all lights */
  668. #if 0
  669.   if (nolight) {
  670.     float value;
  671.  
  672.     l.numlightstyles = 1;
  673.     l.lightstyles[0] = 0;
  674.     value = 300 + 40 * l.facenormal[0] - 50 * l.facenormal[1] +
  675.       60 * l.facenormal[2];
  676.     for (i = 0; i < l.numsurfpt; i++)
  677.       l.lightmaps[0][i] = value;
  678.   }
  679.   else {
  680. #endif
  681.     l.numlightstyles = 0;
  682.     for (i = 0; i < bspMem->nummapentities; i++) {
  683.       if (bspMem->mapentities[i].light)
  684.     SingleLightFace(&bspMem->mapentities[i], &l, faceoffset);
  685.     }
  686.     FixMinlight(&l);
  687.     if (!l.numlightstyles)                    /* no light hitting it */
  688.       return;
  689. #if 0
  690.   }
  691. #endif
  692.  
  693.   /* save out the values */
  694.   for (i = 0; i < MAXLIGHTMAPS; i++)
  695.     f->styles[i] = l.lightstyles[i];
  696.  
  697.   lightmapsize = size * l.numlightstyles;
  698.   f->lightofs = bspMem->shared.quake1.lightdatasize;
  699.   out = GetFileSpace(bspMem, lightmapsize);
  700.  
  701.   /* extra filtering */
  702.   h = (l.texsize[1] + 1) * 2;
  703.   w = (l.texsize[0] + 1) * 2;
  704.  
  705.   for (i = 0; i < l.numlightstyles; i++) {
  706.     if (l.lightstyles[i] == 0xff)
  707.       Error("Wrote empty lightmap");
  708.     light = l.lightmaps[i];
  709.     c = 0;
  710.     for (t = 0; t <= l.texsize[1]; t++)
  711.       for (s = 0; s <= l.texsize[0]; s++, c++) {
  712.     if (bspMem->litOptions & LIGHT_EXTRA) {            /* filtered sample */
  713.       total = light[t * 2 * w + s * 2] +
  714.         light[t * 2 * w + s * 2 + 1] +
  715.         light[(t * 2 + 1) * w + s * 2] +
  716.         light[(t * 2 + 1) * w + s * 2 + 1];
  717.       total *= 0.25;
  718.     }
  719.     else
  720.       total = light[c];
  721.     total *= rangescale;                    /* scale before clamping */
  722.  
  723.     if (total > 255)
  724.       total = 255;
  725.     if (total < 0)
  726.       Error("light < 0");
  727.     *out++ = total;
  728.       }
  729.   }
  730. }
  731.  
  732. void FindFaceOffsets(__memBase)
  733. {
  734.   int i, j;
  735.   struct entity *ent;
  736.   struct dmodel_t *mod;
  737.  
  738.   for (j = bspMem->shared.quake1.dmodels[0].firstface; j < bspMem->shared.quake1.dmodels[0].numfaces; j++) {
  739.     nolightface[j] = FALSE;
  740.   }
  741.   for (i = 1; i < bspMem->shared.quake1.nummodels; i++) {
  742.     mod = &bspMem->shared.quake1.dmodels[i];
  743.     ent = FindEntityWithModel(bspMem, i);
  744.  
  745.     if (!__strncmp(ent->classname, "rotate_", 7)) {
  746.       int start = mod->firstface;
  747.       int end = start + mod->numfaces;
  748.  
  749.       for (j = start; j < end; j++) {
  750.     nolightface[j] = TRUE;
  751.     VectorCopy(ent->origin, faceoffset[j]);
  752.       }
  753.     }
  754.   }
  755. }
  756.  
  757. /*
  758.  * =============
  759.  * LightWorld
  760.  * =============
  761.  */
  762. void LightWorld(__memBase)
  763. {
  764.   int i;
  765.  
  766.   FindFaceOffsets(bspMem);
  767.   for (i = 0; i < bspMem->shared.quake1.numfaces; i++, bspfileface++) {
  768.     LightFace(bspMem, i, nolightface[i], faceoffset[i]);
  769.     mprogress(bspMem->shared.quake1.numfaces, i + 1);
  770.   }
  771. }
  772.  
  773. bool light(__memBase, float scale, float range)
  774. {
  775.   mprintf("----- LightFaces --------\n");
  776.  
  777.   if (scale)
  778.     scaledist = scale;
  779.   if (range)
  780.     rangescale = range;
  781.  
  782.   AllocClusters(bspMem, LUMP_LIGHTING);
  783.  
  784.   if (!(minlights = (float *)kmalloc(sizeof(float) * bspMem->shared.quake1.numfaces)))
  785.       Error(failed_memoryunsize, "minlights");
  786.  
  787.   if (!(nolightface = (bool *) kmalloc(sizeof(bool) * bspMem->shared.quake1.numfaces)))
  788.     Error(failed_memoryunsize, "nolightfaces");
  789.   if (!(faceoffset = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
  790.     Error(failed_memoryunsize, "faceoffsets");
  791.  
  792.   if (bspMem->litOptions & LIGHT_RADIOSITY) {
  793.     if (!(facepatches = (struct patch **)kmalloc(sizeof(struct patch *) * bspMem->shared.quake1.numfaces)))
  794.         Error(failed_memoryunsize, "facepatches");
  795.     if (!(faceentity = (struct entity **)kmalloc(sizeof(struct entity *) * bspMem->shared.quake1.numfaces)))
  796.         Error(failed_memoryunsize, "facentities");
  797.     if (!(facelights = (struct facelight *)kmalloc(sizeof(struct entity *) * bspMem->shared.quake1.numfaces)))
  798.         Error(failed_memoryunsize, "facelights");
  799.     if (!(patches = (struct patch *)kmalloc(sizeof(struct patch) * 4096)))
  800.         Error(failed_memoryunsize, "patches");
  801.  
  802.     if (!(radiosity = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
  803.       Error(failed_memoryunsize, "radiosity");
  804.     if (!(illumination = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numfaces)))
  805.       Error(failed_memoryunsize, "illumination");
  806.     if (!(backplanes = (struct dplane_t *)kmalloc(sizeof(struct dplane_t) * bspMem->shared.quake1.numplanes)))
  807.         Error(failed_memoryunsize, "backplanes");
  808.     if (!(directlights = (struct directlight **)kmalloc(sizeof(struct directlight *) * bspMem->shared.quake1.numleafs)))
  809.         Error(failed_memoryunsize, "directlights");
  810.     if (!(leafparents = (int *)kmalloc(sizeof(int) * bspMem->shared.quake1.numleafs)))
  811.         Error(failed_memoryunsize, "leafparents");
  812.     if (!(nodeparents = (int *)kmalloc(sizeof(int) * bspMem->shared.quake1.numnodes)))
  813.         Error(failed_memoryunsize, "nodeparents");
  814.  
  815.     if (!(texreflectivity = (vec3_t *) kmalloc(sizeof(vec3_t) * bspMem->shared.quake1.numtexinfo)))
  816.       Error(failed_memoryunsize, "texture reflectivity");
  817.   }
  818.  
  819.   if (!(bspMem->litOptions & LIGHT_MEM)) {
  820.     bspMem->mapOptions |= MAP_LOADLIGHTS;
  821.     LoadMapFile(bspMem, bspMem->shared.quake1.dentdata);
  822.   }
  823.  
  824.   MakeTnodes(bspMem, &bspMem->shared.quake1.dmodels[0]);
  825.  
  826.   if (bspMem->litOptions & LIGHT_RADIOSITY)
  827.     RadWorld(bspMem);
  828.   else
  829.     LightWorld(bspMem);
  830.  
  831.   WriteEntitiesToString(bspMem);
  832.   kfree();
  833.  
  834.   return TRUE;
  835. }
  836.